home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / comm / amigatcp.6 < prev    next >
Text File  |  1989-03-18  |  57KB  |  2,568 lines

  1. Path: xanth!ames!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i085:  amigatcp - tcp/ip for the amiga, Part06/06
  5. Message-ID: <12333@swan.ulowell.edu>
  6. Date: 17 Mar 89 23:21:03 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2557
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: rminnich@super.org (Ronald G. Minnich)
  12. Posting-number: Volume 89, Issue 85
  13. Archive-name: comm/amigatcp.6
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    main.c
  23. #    tcpin.c
  24. #    newtelnetp.c
  25. # This archive created: Fri Mar 17 18:00:34 1989
  26. cat << \SHAR_EOF > main.c
  27. /*
  28.  *  Amiga version changes are 
  29.  *
  30.  *  Copyright (c)1987
  31.  *  Louis A. Mamakos
  32.  *
  33.  *  For non-commercial use only.
  34.  */
  35.  
  36. /* Main network program - provides both client and server functions */
  37. #define    NSESSIONS    10    /* Maximum interactive client sessions */
  38. #define HOSTNAMELEN 32        /* changed from 16 by Bdale 860812 */
  39.  
  40. #ifndef    STARTUP
  41. #ifdef    AMIGA
  42. #define    STARTUP "s:net-sequence"
  43. #else
  44. #define    STARTUP    "/autoexec.net"    /* File to read startup commands from */
  45. #endif
  46. #endif
  47.  
  48. #include <stdio.h>
  49. #include "machdep.h"
  50. #include "mbuf.h"
  51. #include "netuser.h"
  52. #include "timer.h"
  53. #include "icmp.h"
  54. #include "iface.h"
  55. #include "ip.h"
  56. #include "tcp.h"
  57. #include "ftp.h"
  58. #include "telnet.h"
  59. #include "session.h"
  60. #include "cmdparse.h"
  61.  
  62. #ifdef    AMIGA
  63. #include "amiga.h"
  64. #else
  65. #include "pc.h"
  66. #endif
  67.  
  68. extern struct interface *ifaces;
  69. struct session sessions[NSESSIONS];
  70. struct session *current;
  71. extern char major_rev[], minor_rev[];
  72.  
  73. int mode;
  74. FILE *logfp;
  75.  
  76. #ifdef    TRACE
  77. #include "trace.h"
  78. int32 trace;
  79. #endif
  80.  
  81. char hostname[HOSTNAMELEN];    
  82. int32 aton();
  83. int16 lport = 1001;
  84. #ifdef    AMIGA
  85. char prompt[] = "\33[1;33mnet>\33[m ";    /* make it standout and stuff */
  86. #else
  87. char prompt[] = "net> ";
  88. #endif
  89. char nospace[] = "No space!!\r\n";    /* Generic malloc fail message */
  90. static char notval[] = "Not a valid TCB\r\n";
  91.  
  92. #ifndef    MSDOS            /* PC uses F-10 key always */
  93. static char escape = 0x1d;    /* default escape character is ^] */
  94. #endif
  95.  
  96. /* Command lookup and branch table */
  97. int go(),cmdmode(),dodigipeat(),
  98.     doipaddr(),dotelnet(),doexit(),doclose(),dohostname(),
  99.     doreset(),dotcpstat(),dotrace(),doescape(),dospeed(),dohelp(),
  100.     dowindow(),doroute(),doecho(),
  101.     dolog(),doipstat(),doicmpstat(),doetherstat(),memstat(),doarp(),
  102.     dosession(),doftp(),domss(),dostart(),dostop(),doattach(),
  103.     domycall(),dosmtptick(),doudpstat(),dottl(),dokiss(),dotcpkick(),
  104.     doeol();
  105.  
  106. #ifdef HAPN
  107. int    dohapnstat();
  108. #endif HAPN
  109. #ifdef AMIGADEVDRV
  110. int    DriverInit(), DriverShutdown(), CheckTcp();
  111. #endif
  112. static struct cmds cmds[] = {
  113.     /* The "go" command must be first */
  114.     "",        go,        0, NULLCHAR,    NULLCHAR,
  115.     "arp",        doarp,        0, NULLCHAR,    NULLCHAR,
  116.     "attach",    doattach,    2,
  117.         "attach <hardware> <hw specific options>", NULLCHAR,
  118.     "close",    doclose,    0, NULLCHAR,    NULLCHAR,
  119. #ifdef    AX25
  120.     "digipeat",    dodigipeat,    0, NULLCHAR,    NULLCHAR,
  121. #endif
  122. #ifdef AMIGADEVDRV
  123.     "checktcp",    CheckTcp,    0, NULLCHAR,    NULLCHAR,
  124.     "driver",    DriverInit,    0, NULLCHAR,    NULLCHAR,
  125.     "driveroff",    DriverShutdown,    0, NULLCHAR,    NULLCHAR,
  126. #endif
  127.     "echo",        doecho,        0, NULLCHAR,    NULLCHAR,   
  128.     "eol",        doeol,        0, NULLCHAR,
  129.         "eol options: unix, standard",
  130. #ifndef    MSDOS
  131.     "escape",    doescape,    0, NULLCHAR,    NULLCHAR,   
  132. #endif
  133. #ifdef    PC_EC
  134.     "etherstat",    doetherstat,    0, NULLCHAR,    NULLCHAR,
  135. #endif  PC_EC
  136.     "exit",        doexit,        0, NULLCHAR,    NULLCHAR,
  137.     "ftp",        doftp,        2, "ftp <address>",    NULLCHAR,
  138. #ifdef HAPN
  139.     "hapnstat",    dohapnstat,    0, NULLCHAR,    NULLCHAR,
  140. #endif HAPN
  141.     "help",        dohelp,        0, NULLCHAR,    NULLCHAR,
  142.     "hostname",    dohostname,    0, NULLCHAR,    NULLCHAR,
  143.     "log",        dolog,        0, NULLCHAR,    NULLCHAR,
  144.     "icmpstat",    doicmpstat,    0, NULLCHAR,    NULLCHAR,
  145.     "ipaddr",    doipaddr,    0, NULLCHAR,    NULLCHAR,
  146.     "ipstat",    doipstat,    0, NULLCHAR,    NULLCHAR,
  147. #ifdef    AX25
  148.     "kiss",        dokiss,        0, NULLCHAR,    NULLCHAR,
  149. #endif
  150.     "smtp",        dosmtptick,    0, NULLCHAR,    NULLCHAR,
  151. #ifndef    AMIGA
  152.     "memstat",    memstat,    0, NULLCHAR,    NULLCHAR,
  153. #endif
  154.     "mss",        domss,        0, NULLCHAR,    NULLCHAR,
  155. #ifdef    AX25
  156.     "mycall",    domycall,    0, NULLCHAR,    NULLCHAR,
  157. #endif
  158.     "reset",    doreset,    0, NULLCHAR,    NULLCHAR,
  159.     "route",    doroute,    0, NULLCHAR,    NULLCHAR,
  160.     "session",    dosession,    0, NULLCHAR,    NULLCHAR,
  161.     "speed",    dospeed,    0, NULLCHAR,    NULLCHAR,
  162. #ifdef    SERVERS
  163.     "start",    dostart,    2, "start <servername>",NULLCHAR,
  164.     "stop",        dostop,        2, "stop <servername>",    NULLCHAR,
  165. #endif
  166.     "tcpstat",    dotcpstat,    0, NULLCHAR,    NULLCHAR,
  167.     "tcpkick",    dotcpkick,    0, NULLCHAR,    NULLCHAR,
  168.     "telnet",    dotelnet,    2, "telnet <address>",    NULLCHAR,
  169.     "trace",    dotrace,    0, NULLCHAR,    NULLCHAR,
  170.     "ttl",        dottl,        0, NULLCHAR,    NULLCHAR,
  171.     "udpstat",    doudpstat,    0, NULLCHAR,    NULLCHAR,
  172.     "window",    dowindow,    0, NULLCHAR,    NULLCHAR,
  173.     "?",        dohelp,        0, NULLCHAR,    NULLCHAR,
  174.     NULLCHAR,    NULLFP,        0,
  175.         "Unknown command; type \"?\" for list",   NULLCHAR, 
  176. };
  177.  
  178. /* "route" subcommands */
  179. int doadd(),dodrop();
  180. static struct cmds rtcmds[] = {
  181.     "add", doadd, 3,
  182.     "route add <dest addr>[/<bits>] <if name> [gateway] [metric]",
  183.     "Add failed",
  184.  
  185.     "drop", dodrop, 2,
  186.     "route drop <dest addr>[/<bits>]",
  187.     "Not in table",
  188.  
  189.     NULLCHAR, NULLFP, 0,
  190.     "route subcommands: add, drop",
  191.     NULLCHAR, 
  192. };
  193.  
  194. #ifdef    SERVERS
  195. /* "start" and "stop" subcommands */
  196. int ftp_start(),smtp_start(),discard_start(),echo_start(),telnet_start();
  197. static struct cmds startcmds[] = {
  198.     "discard",    discard_start,    0, NULLCHAR, NULLCHAR,
  199.     "echo",        echo_start,    0, NULLCHAR, NULLCHAR,
  200.     "ftp",        ftp_start,    0, NULLCHAR, NULLCHAR,
  201.     "smtp",        smtp_start,    0, NULLCHAR, NULLCHAR,
  202.     "telnet",    telnet_start,    0, NULLCHAR, NULLCHAR,
  203.     NULLCHAR,    NULLFP,        0,
  204.         "start options: discard, echo, ftp, smtp, telnet", NULLCHAR,
  205. };
  206. int ftp_stop(),smtp_stop(),echo_stop(),discard_stop(),telnet_stop();
  207. static struct cmds stopcmds[] = {
  208.     "discard",    discard_stop,    0, NULLCHAR, NULLCHAR,
  209.     "echo",        echo_stop,    0, NULLCHAR, NULLCHAR,
  210.     "ftp",        ftp_stop,    0, NULLCHAR, NULLCHAR,
  211.     "smtp",        smtp_stop,    0, NULLCHAR, NULLCHAR,
  212.     "telnet",    telnet_stop,    0, NULLCHAR, NULLCHAR,
  213.     NULLCHAR,    NULLFP,        0,
  214.         "stop options: discard, echo, ftp, smtp, telnet",  NULLCHAR,
  215. };
  216. #endif
  217.  
  218. main(argc,argv)
  219. int argc;
  220. char *argv[];
  221. {
  222.     static char inbuf[BUFSIZ];    /* keep it off the stack */
  223.     int c;
  224.     char *ttybuf,*fgets();
  225.     int16 cnt;
  226.     int ttydriv();
  227.     int cmdparse();
  228.     void check_time();
  229.     FILE *fp;
  230.     struct interface *ifp;
  231. #ifdef    AMIGA
  232.     char    *startup = STARTUP;
  233. #endif
  234.  
  235.     ioinit();
  236.     printf("KA9Q Internet Protocol Package, v%s.%s\n",major_rev,minor_rev);
  237. #ifdef    AMIGA
  238.     if (argc > 1)
  239.         startup = argv[1];
  240.  
  241.     if((fp = fopen(startup,"r")) != NULLFILE){
  242.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  243.             printf(prompt); printf(inbuf);
  244.             cmdparse(cmds, inbuf);
  245.         }
  246.         fclose(fp);
  247.     } else
  248.         printf("Can't read inital commands from %s\n", startup);
  249. #else
  250.     if((fp = fopen(STARTUP,"r")) != NULLFILE){
  251.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  252.             cmdparse(cmds,inbuf);
  253.         }
  254.         fclose(fp);
  255.     }        
  256. #endif
  257.     cmdmode();
  258.     smtpclinit();            /* arm SMTP background client timer */
  259.  
  260.     /* Main commutator loop */
  261.     for(;;){
  262.         /* Process any keyboard input */
  263.         while((c = kbread()) != -1){
  264. #ifdef    MSDOS
  265.             /* c == -2 means the command escape key (F10) */
  266.             if(c == -2){
  267.                 if(mode != CMD_MODE){
  268.                     printf("\r\n");
  269.                     cmdmode();
  270.                 }
  271.                 continue;
  272.             }
  273. #else
  274.             if(c == escape && escape != 0 && mode != CMD_MODE) {
  275.                 printf("\r\n");
  276.                 cmdmode();
  277.                 continue;
  278.             }
  279. #endif
  280.             if((cnt = ttydriv(c,&ttybuf)) == 0)
  281.                 continue;
  282.             switch(mode){
  283.             case CMD_MODE:
  284.                 (void)cmdparse(cmds,ttybuf);
  285.                 fflush(stdout);
  286.                 break;
  287.             case CONV_MODE:
  288. #ifndef    MSDOS
  289.                 if(ttybuf[0] == escape && escape != 0){
  290.                     printf("\r\n");
  291.                     cmdmode();
  292.                 } else
  293. #endif MSDOS
  294.                     if(current->parse != NULLFP)
  295.                         (*current->parse)(ttybuf,cnt);
  296.  
  297.                 break;
  298.             }
  299.             if(mode == CMD_MODE){
  300.                 printf(prompt);
  301.                 fflush(stdout);
  302.             }
  303.         }
  304.         /* Service the interfaces */
  305.         for(ifp = ifaces; ifp != NULLIF; ifp = ifp->next){
  306.             if(ifp->recv != NULLFP)
  307.                 (*ifp->recv)(ifp);
  308.         }
  309.  
  310.         /* Service the clock if it has ticked */
  311.         check_time();
  312. #ifdef AMIGADEVDRV
  313.         /* check device driver open request */
  314.         check_driver();
  315.         CheckTcp();
  316. #else
  317. #ifdef    MSDOS
  318.         /* Tell DoubleDos to let the other task run for awhile.
  319.          * If DoubleDos isn't active, this is a no-op
  320.          */
  321.         giveup();
  322. #else
  323.         /* Wait until interrupt, then do it all over again */
  324.         eihalt();
  325. #endif
  326. #endif AMIGADEVDRV
  327.     }
  328. }
  329.  
  330. /* Enter command mode */
  331. int
  332. cmdmode()
  333. {
  334.     if(mode != CMD_MODE){
  335.         mode = CMD_MODE;
  336.         cooked();
  337.         printf(prompt);
  338.         fflush(stdout);
  339.     }
  340.     return 0;
  341. }
  342. /* Select and display sessions */
  343. static
  344. dosession(argc,argv)
  345. int argc;
  346. char *argv[];
  347. {
  348.     unsigned i;
  349.     struct session *s;
  350.     extern char *tcpstates[];
  351.     char *psocket();
  352.  
  353.     if(argc < 2){
  354.         printf(" #  Type    Remote socket          TCB  State\r\n");
  355.         for(s=sessions;s < & sessions[NSESSIONS];s++){
  356.             switch(s->type){
  357.             case TELNET:
  358. #ifndef    AMIGA
  359.                 printf("%c%-3d%Telnet  %-23s%4x %-s\r\n",
  360.                     (current == s)? '*':' ',
  361.                     s - sessions,
  362.                     psocket(&s->cb.telnet->tcb->conn.remote),
  363.                     (int)s->cb.telnet->tcb,
  364.                     tcpstates[s->cb.telnet->tcb->state]);
  365. #else
  366.                 printf("%c%-3d%Telnet  %-23s%6lx %-s\r\n",
  367.                     (current == s)? '*':' ',
  368.                     s - sessions,
  369.                     psocket(&s->cb.telnet->tcb->conn.remote),
  370.                     (unsigned long)s->cb.telnet->tcb,
  371.                     tcpstates[s->cb.telnet->tcb->state]);
  372. #endif                break;
  373.             case FTP:
  374. #ifndef    AMIGA
  375.                 printf("%c%-3d%FTP     %-23s%4x %-s\r\n",
  376.                     (current == s)? '*':' ',
  377.                     s - sessions,
  378.                     psocket(&s->cb.ftp->control->conn.remote),
  379.                     (int)s->cb.ftp->control,
  380.                     tcpstates[s->cb.ftp->control->state]);
  381. #else
  382.                 printf("%c%-3d%FTP     %-23s%6lx %-s\r\n",
  383.                     (current == s)? '*':' ',
  384.                     s - sessions,
  385.                     psocket(&s->cb.ftp->control->conn.remote),
  386.                     (unsigned long)s->cb.ftp->control,
  387.                     tcpstates[s->cb.ftp->control->state]);
  388. #endif
  389.                 break;
  390.             }
  391.         }
  392.         return 0;
  393.     }
  394.     i = atoi(argv[1]);
  395.     if(i > NSESSIONS){
  396.         printf("Invalid session: %d\r\n",i);
  397.         return 1;
  398.     }
  399.     if(sessions[i].type == FREE){
  400.         printf("Inactive session: %d\r\n",i);
  401.         return 1;
  402.     }
  403.     current = &sessions[i];
  404.     go();
  405.     return 0;
  406. }
  407. /* Enter conversational mode with current session */
  408. int
  409. go()
  410. {
  411.     void rcv_char(),r_ctl();
  412.  
  413.     if(current == NULLSESSION || current->type == FREE)
  414.         return 0;
  415.     mode = CONV_MODE;
  416.     switch(current->type){
  417.     case TELNET:
  418.         if(current->cb.telnet->remote[TN_ECHO])
  419.             raw();    /* Re-establish raw mode if it was set */
  420.         rcv_char(current->cb.telnet->tcb,0); /* Get any pending input */
  421.         break;
  422.     case FTP:
  423.         r_ctl(current->cb.ftp->control,0);
  424.         break;
  425.     }
  426.     return 0;
  427. }
  428. #ifdef    AX25
  429. extern int digipeat;
  430. dodigipeat(argc,argv)
  431. int argc;
  432. char *argv[];
  433. {
  434.     if(argc == 1) {
  435.         printf("digipeat %s\r\n",digipeat ? "on" : "off");
  436.     } else {
  437.         if(strcmp(argv[1],"on") == 0)
  438.             digipeat = 1;
  439.         else
  440.             digipeat = 0;
  441.     }
  442. }
  443. #endif
  444. static
  445. doipaddr(argc,argv)
  446. int argc;
  447. char *argv[];
  448. {
  449.     char *inet_ntoa();
  450.  
  451.     if(argc < 2)
  452.         printf("%s\r\n",inet_ntoa(ip_addr));
  453.     else
  454.         ip_addr = aton(argv[1]);
  455.     return 0;
  456. }
  457. static
  458. doexit(argc,argv)
  459. int argc;
  460. char *argv[];
  461. {
  462.     iostop();
  463.     DriverShutdown();
  464.     exit(0);
  465. }
  466. static
  467. doclose(argc,argv)
  468. int argc;
  469. char *argv[];
  470. {
  471.     if(current == NULLSESSION){
  472.         printf("No current session\r\n");
  473.         return 0;
  474.     }
  475.     switch(current->type){
  476.     case TELNET:
  477.         close_tcp(current->cb.telnet->tcb);
  478.         break;
  479.     case FTP:
  480.         close_tcp(current->cb.ftp->control);
  481.         break;
  482.     }
  483.     return 0;
  484. }
  485. static
  486. doreset(argc,argv)
  487. int argc;
  488. char *argv[];
  489. {
  490.     long htol();
  491.     struct tcb *tcb;
  492.  
  493.     if(argc < 2){
  494.         if(current == NULLSESSION){
  495.             printf("No current session\r\n");
  496.             return 1;
  497.         }
  498.         switch(current->type){
  499.         case TELNET:
  500.             tcb = current->cb.telnet->tcb;
  501.             break;
  502.         case FTP:
  503.             tcb = current->cb.ftp->control;
  504.             break;
  505.         }
  506.     } else
  507.         tcb = (struct tcb *)htol(argv[1]);
  508.     if(!tcpval(tcb)){
  509.         printf(notval);
  510.         return 1;
  511.     }
  512.     close_self(tcb,RESET);
  513.     return 0;
  514. }
  515. static
  516. int
  517. dotcpstat(argc,argv)
  518. int argc;
  519. char *argv[];
  520. {
  521.     long htol();
  522.     register struct tcb *tcb;
  523.  
  524.     if(argc < 2){
  525.         tcpstat();
  526.     } else {
  527.         tcb = (struct tcb *)htol(argv[1]);
  528.         if(tcpval(tcb))
  529.             state_tcp(tcb);
  530.         else
  531.             printf(notval);
  532.     }
  533.     return 0;
  534. }
  535. static
  536. int
  537. dotcpkick(argc,argv)
  538. int argc;
  539. char *argv[];
  540. {
  541.     long htol();
  542.     register struct tcb *tcb;
  543.     void tcp_timeout();
  544.  
  545.     if(argc < 2){
  546.         if(current == NULLSESSION){
  547.             printf("No current session\r\n");
  548.             return 1;
  549.         }
  550.         switch(current->type){
  551.         case TELNET:
  552.             tcb = current->cb.telnet->tcb;
  553.             break;
  554.         case FTP:
  555.             tcb = current->cb.ftp->control;
  556.             break;
  557.         }
  558.     } else
  559.         tcb = (struct tcb *)htol(argv[1]);
  560.  
  561.     if(!tcpval(tcb)){
  562.         printf(notval);
  563.         return 1;
  564.     }
  565.     if(argc > 2){
  566.         /* Optional value for SRTT */
  567.         tcb->srtt = atoi(argv[2]);
  568.     }
  569.     /* Don't actually do anything unless something is pending */
  570.     if(tcb->sndcnt != 0){
  571.         tcb->retry = 0;
  572.         tcp_timeout((int *)tcb);
  573.     }
  574.     return 0;
  575. }
  576. static
  577. int
  578. dotrace(argc,argv)
  579. int argc;
  580. char *argv[];
  581. {
  582.     long htol();
  583. #ifdef TRACE
  584.     if(argc < 2)
  585.         printf("trace level 0x%08lx\r\n",trace);
  586.     else
  587.         trace = htol(argv[1]);
  588.     return 0;
  589. #else
  590.     printf("Trace not enabled - recompile with TRACE defined\r\n");
  591. #endif
  592. }
  593. static
  594. dohostname(argc,argv)
  595. int argc;
  596. char *argv[];
  597. {
  598.     char *strncpy();
  599.  
  600.     if(argc < 2)
  601.         printf("%s\r\n",hostname);
  602.     else 
  603.         strncpy(hostname,argv[1],HOSTNAMELEN);
  604.     return 0;
  605. }
  606. static
  607. int
  608. dolog(argc,argv)
  609. int argc;
  610. char *argv[];
  611. {
  612.     char *strncpy();
  613.  
  614. #ifdef    AMIGA
  615.     static char logname[45];  /* long enough for CON:10/10/300/300/title */
  616. #else
  617.     static char logname[15];
  618. #endif
  619.     if(argc < 2){
  620.         if(logfp)
  621.             printf("Logging to %s\r\n",logname);
  622.         else
  623.             printf("Logging off\r\n");
  624.         return 0;
  625.     }
  626.     if(logfp){
  627.         fclose(logfp);
  628.         logfp = NULLFILE;
  629.     }
  630.     if(strcmp(argv[1],"stop") != 0){
  631. #ifdef    AMIGA
  632.         strncpy(logname,argv[1],45);
  633. #else
  634.         strncpy(logname,argv[1],15);
  635. #endif
  636.         logfp = fopen(logname,"a+");
  637.     }
  638.     return 0;
  639. }
  640. #ifndef    MSDOS
  641. static
  642. int
  643. doescape(argc,argv)
  644. int argc;
  645. char *argv[];
  646. {
  647.     if(argc < 2)
  648.         printf("0x%x\r\n",escape);
  649.     else 
  650.         escape = *argv[1];
  651.     return 0;
  652. }
  653. #endif    MSDOS
  654. static
  655. int
  656. dohelp(argc,argv)
  657. int argc;
  658. char *argv[];
  659. {
  660.     register struct cmds *cmdp;
  661.     int i,j;
  662.  
  663.     printf("Main commands:\r\n");
  664.     for(i=0,cmdp = cmds;cmdp->name != NULL;cmdp++,i++){
  665.         printf("%s",cmdp->name);
  666.         if((i % 4) == 3)
  667.             printf("\r\n");
  668.         else {
  669.             for(j=strlen(cmdp->name);j < 16; j++)
  670.                 putchar(' ');
  671.         }
  672.     }
  673.     if((i % 4) != 0)
  674.         printf("\r\n");
  675.     return 0;
  676. }
  677. static
  678. int
  679. domss(argc,argv)
  680. int argc;
  681. char *argv[];
  682. {
  683.     if(argc < 2)
  684.         printf("%d\r\n",tcp_mss);
  685.     else
  686.         tcp_mss = atoi(argv[1]);
  687.     return 0;
  688. }
  689. static
  690. int
  691. dowindow(argc,argv)
  692. int argc;
  693. char *argv[];
  694. {
  695.     if(argc < 2)
  696.         printf("%d\r\n",tcp_window);
  697.     else
  698.         tcp_window = atoi(argv[1]);
  699.     return 0;
  700. }
  701. static
  702. int
  703. dottl(argc,argv)
  704. char *argv[];
  705. {
  706.     if(argc < 2)
  707.         printf("%u\r\n",ip_ttl & 0xff);
  708.     else
  709.         ip_ttl = atoi(argv[1]);
  710.     return 0;
  711. }
  712. struct session *
  713. newsession()
  714. {
  715.     register int i;
  716.  
  717.     for(i=0;i<NSESSIONS;i++)
  718.         if(sessions[i].type == FREE)
  719.             return &sessions[i];
  720.     return NULLSESSION;
  721. }
  722. freesession(s)
  723. struct session *s;
  724. {
  725.     if(s != NULLSESSION)
  726.         s->type = FREE;
  727. }
  728. /* Display and/or manipulate routing table */
  729. int
  730. doroute(argc,argv)
  731. int argc;
  732. char *argv[];
  733. {
  734.     if(argc < 2){
  735.         dumproute();
  736.         return 0;
  737.     }
  738.     return subcmd(rtcmds,argc,argv);
  739. }
  740. /* Add an entry to the routing table
  741.  * E.g., "add 1.2.3.4 ax0 5.6.7.8 3"
  742.  */
  743. int
  744. doadd(argc,argv)
  745. int argc;
  746. char *argv[];
  747. {
  748.     struct interface *ifp;
  749.     int32 dest,gateway;
  750.     unsigned bits;
  751.     char *bitp,*index();
  752.     int metric;
  753.  
  754.     if(strcmp(argv[1],"default") == 0){
  755.         dest = 0;
  756.         bits = 0;
  757.     } else {
  758.         dest = aton(argv[1]);
  759.  
  760.         /* If IP address is followed by an optional slash and
  761.          * a length field, (e.g., 128.96/16) get it;
  762.          * otherwise assume a full 32-bit address
  763.          */
  764.         if((bitp = index(argv[1],'/')) != NULLCHAR){
  765.             bitp++;
  766.             bits = atoi(bitp);
  767.         } else
  768.             bits = 32;
  769.     }
  770.     for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
  771.         if(strcmp(argv[2],ifp->name) == 0)
  772.             break;
  773.     }
  774.     if(ifp == NULL){
  775.         printf("Interface \"%s\" unknown\r\n",argv[2]);
  776.         return 1;
  777.     }
  778.     if(argc > 3)
  779.         gateway = aton(argv[3]);
  780.     else
  781.         gateway = 0;
  782.  
  783.     if(argc > 4)
  784.         metric = atoi(argv[4]);
  785.     else
  786.         metric = 0;
  787.  
  788.     rt_add(dest,bits,gateway,metric,ifp);
  789.     return 0;
  790. }
  791. /* Drop an entry from the routing table
  792.  * E.g., "drop 128.96/16
  793.  */
  794. int
  795. dodrop(argc,argv)
  796. int argc;
  797. char *argv[];
  798. {
  799.     char *bitp,*index();
  800.     unsigned bits;
  801.  
  802.     /* If IP address is followed by an optional slash and length field,
  803.      * (e.g., 128.96/16) get it; otherwise assume a full 32-bit address
  804.      */
  805.     if((bitp = index(argv[1],'/')) != NULLCHAR){
  806.         bitp++;
  807.         bits = atoi(bitp);
  808.     } else
  809.         bits = 32;
  810.  
  811.     return rt_drop(aton(argv[1]),bits);
  812. }
  813.  
  814. #ifdef SERVERS
  815. dostart(argc,argv)
  816. int argc;
  817. char *argv[];
  818. {
  819.     return subcmd(startcmds,argc,argv);
  820. }
  821. dostop(argc,argv)
  822. int argc;
  823. char *argv[];
  824. {
  825.     return subcmd(stopcmds,argc,argv);
  826. }
  827. #endif SERVERS
  828.  
  829. doecho(argc,argv)
  830. int argc;
  831. char *argv[];
  832. {
  833.     extern int refuse_echo;
  834.  
  835.     if(argc < 2){
  836.         if(refuse_echo)
  837.             printf("Refuse\r\n");
  838.         else
  839.             printf("Accept\r\n");
  840.     } else {
  841.         if(strcmp(argv[1],"refuse") == 0)
  842.             refuse_echo = 1;
  843.         else if(strcmp(argv[1],"accept") == 0)
  844.             refuse_echo = 0;
  845.         else
  846.             return -1;
  847.     }
  848.     return 0;
  849. }
  850. /* set for unix end of line for remote echo mode telnet */
  851. doeol(argc,argv)
  852. int argc;
  853. char *argv[];
  854. {
  855.     extern int unix_line_mode;
  856.  
  857.     if(argc < 2){
  858.         if(unix_line_mode)
  859.             printf("Unix\r\n");
  860.         else
  861.             printf("Standard\r\n");
  862.     } else {
  863.         if(strcmp(argv[1],"unix") == 0)
  864.             unix_line_mode = 1;
  865.         else if(strcmp(argv[1],"standard") == 0)
  866.             unix_line_mode = 0;
  867.         else {
  868.             return -1;
  869.         }
  870.     }
  871.     return 0;
  872. }
  873. /* List of supported hardware devices */
  874. #ifdef    PC_EC
  875. int ec_attach();
  876. #endif
  877.  
  878. int asy_attach();
  879.  
  880. #ifdef    PC100
  881. int pc_attach();
  882. #endif
  883.  
  884. #ifdef HAPN
  885. int hapn_attach();
  886. #endif
  887.  
  888. #ifdef    NETROM
  889. int netrom_attach();
  890. #endif
  891.  
  892. struct cmds attab[] = {
  893. #ifdef    NETROM
  894.     /* NET/ROM virtual interface using companion asy interface in AX.25 mode */
  895.     "netrom", netrom_attach, 4,
  896.     "attach netrom <asy-intf> ax25 <label> [mtu [ upd-freq ]]",
  897.     "Could not attach NET/ROM virtual interface",
  898. #endif
  899. #ifdef    PC_EC
  900.     /* 3-Com Ethernet interface */
  901.     "3c500", ec_attach, 7, 
  902.     "attach 3c500 <address> <vector> arpa <label> <buffers> <mtu>",
  903.     "Could not attach 3c500",
  904. #endif
  905.     /* Ordinary PC asynchronous adaptor */
  906.     "asy", asy_attach, 8, 
  907.     "attach asy <address> <vector> slip|ax25 <label> <buffers> <mtu> <speed>",
  908.     "Could not attach asy",
  909. #ifdef    PC100
  910.     /* PACCOMM PC-100 8530 HDLC adaptor */
  911.     "pc100", pc_attach, 8, 
  912.     "attach pc100 <address> <vector> ax25 <label> <buffers> <mtu> <speed>",
  913.     "Could not attach pc100",
  914. #endif
  915. #ifdef    HAPN
  916.     /* Hamilton Area Packet Radio (HAPN) 8273 HDLC adaptor */
  917.     "hapn", hapn_attach, 8,
  918.     "attach hapn <address> <vector> ax25 <label> <rx bufsize> <mtu> csma|full",
  919.     "Could not attach hapn",
  920. #endif
  921.     NULLCHAR, NULLFP, 0,
  922.     "Unknown device",
  923.     NULLCHAR,
  924. };
  925.  
  926. /* Attach an interface
  927.  * Syntax: attach <hw type> <I/O address> <vector> <mode> <label> <bufsize> [<speed>]
  928.  */
  929. doattach(argc,argv)
  930. int argc;
  931. char *argv[];
  932. {
  933.     return subcmd(attab,argc,argv);
  934. }
  935. int
  936. dospeed(argc,argv)
  937. int argc;
  938. char *argv[];
  939. {
  940.     int i;
  941.  
  942.     if(argc < 3){
  943.         for(i=0;i < nasy; i++){
  944.             printf("%d: %d bps\r\n",i,asy[i].speed);
  945.         }
  946.         return 0;
  947.     }
  948.     i = atoi(argv[1]);
  949.     if(i >= nasy){
  950.         printf("Line %d out of range\r\n",i);
  951.         return 0;
  952.     }
  953.     asy_speed(i,atoi(argv[2]));
  954.     return i;
  955. }
  956.  
  957. /* Log messages of the form
  958.  * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
  959.  */
  960. /*VARARGS2*/
  961. log(tcb,fmt,arg1,arg2,arg3,arg4)
  962. struct tcb *tcb;
  963. char *fmt;
  964. int arg1,arg2,arg3,arg4;
  965. {
  966.     char *cp,*cp1,*ctime(),*index();
  967.     long t;
  968.  
  969.     if(logfp == NULLFILE)
  970.         return;
  971.     time(&t);
  972.     cp = ctime(&t);
  973.     if((cp1 = index(cp,'\n')) != NULLCHAR)
  974.         *cp1 = '\0';
  975.     fprintf(logfp,"%s %s - ",cp,psocket(&tcb->conn.remote));
  976.     fprintf(logfp,fmt,arg1,arg2,arg3,arg4);
  977.     fprintf(logfp,"\n");
  978.     fflush(logfp);
  979. }
  980. /* Define null definitions for unused interfaces to avoid pulling in code
  981.  * from the library
  982.  */
  983. #ifndef    ETHER
  984. int ec_output() {}
  985. int pether() {}
  986. int gether() {}
  987. char *ether_bdcst = NULLCHAR;
  988. #endif ETHER
  989.  
  990. #ifndef AX25
  991. int setcall() {}
  992. int psax25() {}
  993. struct ax25_addr ax25_bdcst,mycall;
  994. #endif AX25
  995. SHAR_EOF
  996. cat << \SHAR_EOF > tcpin.c
  997. /* Process incoming TCP segments. Page number references are to ARPA RFC-793,
  998.  * the TCP specification.
  999.  */
  1000.  
  1001. #include "machdep.h"
  1002. #include "timer.h"
  1003. #include "mbuf.h"
  1004. #include "netuser.h"
  1005. #include "internet.h"
  1006. #include "tcp.h"
  1007. #include "icmp.h"
  1008. #include "ip.h"
  1009.  
  1010. struct tcp_stat tcp_stat;
  1011.  
  1012. /* This function is called from IP with the IP header in machine byte order,
  1013.  * along with a mbuf chain pointing to the TCP header.
  1014.  */
  1015. void
  1016. tcp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  1017. struct mbuf *bp;    /* Data field, if any */
  1018. char protocol;        /* Should always be TCP_PTCL */
  1019. int32 source;        /* Remote IP address */
  1020. int32 dest;        /* Our IP address */
  1021. char tos;        /* Type of Service */
  1022. int16 length;        /* Length of data field */
  1023. char rxbroadcast;    /* Incoming broadcast - discard if true */
  1024. {
  1025.     void reset(),update();
  1026.     void proc_syn(),send_syn(),add_reseq(),get_reseq();
  1027.  
  1028.     register struct tcb *tcb;    /* TCP Protocol control block */
  1029.     struct tcp_header seg;        /* Local copy of segment header */
  1030.     int16 mss;            /* Incoming MSS, if any */
  1031.     struct connection conn;        /* Local copy of addresses */
  1032.     struct pseudo_header ph;    /* Pseudo-header for checksumming */
  1033.     int16 optlen;            /* Length of TCP options */
  1034.  
  1035.     if(bp == NULLBUF)
  1036.         return;
  1037.  
  1038.     if(rxbroadcast){
  1039.         /* Any TCP packet arriving as a broadcast is
  1040.          * to be completely IGNORED!!
  1041.          */
  1042.         tcp_stat.bdcsts++;
  1043.         free_p(bp);
  1044.     }
  1045.     ph.source = source;
  1046.     ph.dest = dest;
  1047.     ph.protocol = protocol;
  1048.     ph.zero = 0;
  1049.     ph.length = length;
  1050.     if(cksum(&ph,bp,length) != 0){
  1051.         /* Checksum failed, ignore segment completely */
  1052.         tcp_stat.checksum++;
  1053.         free_p(bp);
  1054.         return;
  1055.     }
  1056.     /* Form local copy of TCP header in host byte order */
  1057.     if(pullup(&bp,(char *)&seg,sizeof(struct tcp_header))
  1058.          != sizeof(struct tcp_header)){
  1059.         /* TCP header is too small */
  1060.         tcp_stat.runt++;
  1061.         free_p(bp);
  1062.         return;
  1063.     }
  1064.     length -= sizeof(struct tcp_header);
  1065.     seg.source = ntohs(seg.source);
  1066.     seg.dest = ntohs(seg.dest);
  1067.     seg.seq = ntohl(seg.seq);
  1068.     seg.ack = ntohl(seg.ack);
  1069.     seg.wnd = ntohs(seg.wnd);
  1070.     seg.up = ntohs(seg.up);    /* Unused as of yet */
  1071.  
  1072.     /* Examine options, if any (there can only be MSS). */
  1073.     optlen = hinibble(seg.offset) * sizeof(long) - sizeof(struct tcp_header);
  1074.     if(optlen != 0){
  1075.         struct mss *mssp;
  1076.  
  1077.         mssp = (struct mss *)bp->data;
  1078.         if(mssp->kind == MSS_KIND && mssp->length == MSS_LENGTH){
  1079.             mss = ntohs(mssp->mss);
  1080.         }
  1081.         pullup(&bp,NULLCHAR,optlen);
  1082.         length -= optlen;
  1083.     } else {
  1084.         mss = 0;
  1085.     }
  1086.     /* Fill in connection structure and find TCB */
  1087.     conn.local.address = dest;
  1088.     conn.local.port = seg.dest;
  1089.     conn.remote.address = source;
  1090.     conn.remote.port = seg.source;
  1091.     
  1092.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  1093.         struct tcb *ntcb;
  1094.         char *malloc();
  1095.         void link_tcb();
  1096.  
  1097.         /* Check that this segment carries a SYN, and that
  1098.          * there's a LISTEN on this socket with
  1099.          * unspecified source address and port
  1100.          */
  1101.         conn.remote.address = 0;
  1102.         conn.remote.port = 0;
  1103.         if(!(seg.flags & SYN) || (tcb = lookup_tcb(&conn)) == NULLTCB){
  1104.             /* No unspecified LISTEN either, so reject */
  1105.             free_p(bp);
  1106.             reset(source,dest,tos,length,&seg);
  1107.             return;
  1108.         }
  1109.         /* We've found an unspecified remote socket, so clone the TCB
  1110.          * and stuff the foreign socket into the clone.
  1111.          */
  1112.         if((ntcb = (struct tcb *)malloc(sizeof (struct tcb))) == NULLTCB){
  1113.             free_p(bp);
  1114.             /* This may fail, but we should at least try */
  1115.             reset(source,dest,tos,length,&seg);
  1116.             return;
  1117.         }
  1118.         bcopy((char *)tcb,(char *)ntcb,sizeof(struct tcb));
  1119.         tcb = ntcb;
  1120.         tcb->conn.remote.address = source;
  1121.         tcb->conn.remote.port = seg.source;
  1122.         tcb->timer.arg = (int *)tcb;
  1123.         link_tcb(tcb);
  1124.     }
  1125.     /* Do unsynchronized-state processing (p. 65-68) */
  1126.     switch(tcb->state){
  1127.     case CLOSED:
  1128.         free_p(bp);
  1129.         reset(source,dest,tos,length,&seg);
  1130.         return;
  1131.     case LISTEN:
  1132.         if(seg.flags & RST){
  1133.             free_p(bp);
  1134.             return;
  1135.         }
  1136.         if(seg.flags & ACK){
  1137.             free_p(bp);
  1138.             reset(source,dest,tos,length,&seg);
  1139.             return;
  1140.         }
  1141.         if(seg.flags & SYN){
  1142.  
  1143.             /* (Security check is bypassed) */
  1144.             /* page 66 */
  1145.             tcp_stat.conin++;
  1146.             proc_syn(tcb,tos,&seg,mss);
  1147.             send_syn(tcb);
  1148.             setstate(tcb,SYN_RECEIVED);        
  1149.             if(length != 0 || seg.flags & FIN) {
  1150.                 break;        /* Continue processing if there's more */
  1151.             }
  1152.             tcp_output(tcb);
  1153.         }
  1154.         free_p(bp);    /* Unlikely to get here directly */
  1155.         return;
  1156.     case SYN_SENT:
  1157.         if(seg.flags & ACK){
  1158.             if(!seq_within(seg.ack,tcb->iss+1,tcb->snd.nxt)){
  1159.                 free_p(bp);
  1160.                 reset(source,dest,tos,length,&seg);
  1161.                 return;
  1162.             }
  1163.         }
  1164.         if(seg.flags & RST){    /* p 67 */
  1165.             if(seg.flags & ACK){
  1166.                 /* The ack must be acceptable since we just checked it.
  1167.                  * This is how the remote side refuses connect requests.
  1168.                  */
  1169.                 close_self(tcb,RESET);
  1170.             }
  1171.             free_p(bp);
  1172.             return;
  1173.         }
  1174.         /* (Security check skipped here) */
  1175.         /* Check incoming precedence; it must match if there's an ACK */
  1176.         if((seg.flags & ACK) && PREC(tos) != PREC(tcb->tos)){
  1177.             free_p(bp);
  1178.             reset(source,dest,tos,length,&seg);
  1179.             return;
  1180.         }
  1181.         if(seg.flags & SYN){
  1182.             proc_syn(tcb,tos,&seg,mss);
  1183.             if(seg.flags & ACK){
  1184.                 /* Our SYN has been acked, otherwise the ACK
  1185.                  * wouldn't have been valid.
  1186.                  */
  1187.                 update(tcb,&seg);
  1188.                 setstate(tcb,ESTABLISHED);
  1189.             } else {
  1190.                 setstate(tcb,SYN_RECEIVED);
  1191.             }
  1192.             if(length != 0 || (seg.flags & FIN)) {
  1193.                 break;        /* Continue processing if there's more */
  1194.             }
  1195.             tcp_output(tcb);
  1196.         } else {
  1197.             free_p(bp);    /* Ignore if neither SYN or RST is set */
  1198.         }
  1199.         return;
  1200.     }
  1201.     /* We reach this point directly in any synchronized state. Note that
  1202.      * if we fell through from LISTEN or SYN_SENT processing because of a
  1203.      * data-bearing SYN, window trimming and sequence testing "cannot fail".
  1204.      */
  1205.  
  1206.     /* Trim segment to fit receive window. */
  1207.     if(trim(tcb,&seg,&bp,&length) == -1){
  1208.         /* Segment is unacceptable */
  1209.         if(!(seg.flags & RST)){
  1210.             tcb->force = 1;
  1211.             tcp_output(tcb);
  1212.         }
  1213.         return;
  1214.     }
  1215.     /* If segment isn't the next one expected, and there's data
  1216.      * or flags associated with it, put it on the resequencing
  1217.      * queue and return. Don't send anything in reply.
  1218.      *
  1219.      * Processing the ACK in an out-of-sequence segment without
  1220.      * flags or data should be safe, however.
  1221.      */
  1222.     if(seg.seq != tcb->rcv.nxt
  1223.      && (length != 0 || (seg.flags & (SYN|FIN)) )){
  1224.         add_reseq(tcb,tos,&seg,bp,length);
  1225.         return;
  1226.     }
  1227.     /* This loop first processes the current segment, and then
  1228.      * repeats if it can process the resequencing queue.
  1229.      */
  1230.     for(;;){
  1231.         /* We reach this point with an acceptable segment; all data and flags
  1232.          * are in the window, and the starting sequence number equals rcv.nxt
  1233.          * (p. 70)
  1234.          */    
  1235.         if(seg.flags & RST){
  1236.             switch(tcb->state){
  1237.             case SYN_RECEIVED:
  1238.                 setstate(tcb,LISTEN);
  1239.                 free_p(bp);
  1240.                 return;
  1241.             default:
  1242.                 close_self(tcb,RESET);
  1243.                 free_p(bp);
  1244.                 return;
  1245.             }
  1246.         }
  1247.         /* (Security check skipped here) p. 71 */
  1248.         /* Check for precedence mismatch or erroneous extra SYN */
  1249.         if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){
  1250.             free_p(bp);
  1251.             reset(source,dest,tos,length,&seg);
  1252.             return;
  1253.         }
  1254.         /* Check ack field p. 72 */
  1255.         if(!(seg.flags & ACK)){
  1256.             free_p(bp);    /* All segments after synchronization must have ACK */
  1257.             return;
  1258.         }
  1259.         /* Process ACK */
  1260.         switch(tcb->state){
  1261.         case SYN_RECEIVED:
  1262.             if(seq_within(seg.ack,tcb->snd.una+1,tcb->snd.nxt)){
  1263.                 update(tcb,&seg);
  1264.                 setstate(tcb,ESTABLISHED);
  1265.             } else {
  1266.                 free_p(bp);
  1267.                 reset(source,dest,tos,length,&seg);
  1268.                 return;
  1269.             }
  1270.             break;
  1271.         case ESTABLISHED:
  1272.         case CLOSE_WAIT:
  1273.             update(tcb,&seg);
  1274.             break;
  1275.         case FINWAIT1:    /* p. 73 */
  1276.             update(tcb,&seg);
  1277.             if(tcb->sndcnt == 0){
  1278.                 /* Our FIN is acknowledged */
  1279.                 setstate(tcb,FINWAIT2);
  1280.             }
  1281.             break;
  1282.         case FINWAIT2:
  1283.             update(tcb,&seg);
  1284.             break;
  1285.         case CLOSING:
  1286.             update(tcb,&seg);
  1287.             if(tcb->sndcnt == 0){
  1288.                 /* Our FIN is acknowledged */
  1289.                 setstate(tcb,TIME_WAIT);
  1290.                 tcb->timer.start = MSL2;
  1291.                 start_timer(&tcb->timer);
  1292.             }
  1293.             break;
  1294.         case LAST_ACK:
  1295.             update(tcb,&seg);
  1296.             if(tcb->sndcnt == 0){
  1297.                 /* Our FIN is acknowledged, close connection */
  1298.                 close_self(tcb,NORMAL);
  1299.                 return;
  1300.             }            
  1301.         case TIME_WAIT:
  1302.             tcb->force = 1;
  1303.             start_timer(&tcb->timer);
  1304.         }
  1305.  
  1306.         /* (URGent bit processing skipped here) */
  1307.  
  1308.         /* Process the segment text, if any, beginning at rcv.nxt (p. 74) */
  1309.         if(length != 0){
  1310.             switch(tcb->state){
  1311.             case SYN_RECEIVED:
  1312.             case ESTABLISHED:
  1313.             case FINWAIT1:
  1314.             case FINWAIT2:
  1315.                 /* Place on receive queue */
  1316.                 append(&tcb->rcvq,bp);
  1317.                 tcb->rcvcnt += length;
  1318.                 tcb->rcv.nxt += length;
  1319.                 tcb->rcv.wnd -= length;
  1320.                 tcb->force = 1;
  1321.                 break;
  1322.             default:
  1323.                 /* Ignore segment text */
  1324.                 free_p(bp);
  1325.                 break;
  1326.             }
  1327.         }
  1328.         /* If the user has set up a r_upcall function, AND
  1329.          * the receive window is more than half full OR
  1330.          * has the urg, push or fin flags set, notify him.
  1331.          *
  1332.          * All this is done before sending an acknowledgement,
  1333.          * to give the user a chance to piggyback some reply data.
  1334.          * It's also done before processing FIN so that the state
  1335.          * change upcall will occur after the user has had a chance
  1336.          * to read the last of the incoming data.
  1337.          */
  1338.         if(tcb->r_upcall){
  1339.             if(tcb->rcvcnt >= tcb->rcv.wnd || (seg.flags & (FIN|URG|PSH))){
  1340.                 (*tcb->r_upcall)(tcb,tcb->rcvcnt);
  1341.             }
  1342.         }
  1343.         /* process FIN bit (p 75) */
  1344.         if(seg.flags & FIN){
  1345.             tcb->force = 1;    /* Always respond with an ACK */
  1346.  
  1347.             switch(tcb->state){
  1348.             case SYN_RECEIVED:
  1349.             case ESTABLISHED:
  1350.                 tcb->rcv.nxt++;
  1351.                 setstate(tcb,CLOSE_WAIT);
  1352.                 break;
  1353.             case FINWAIT1:
  1354.                 tcb->rcv.nxt++;
  1355.                 if(tcb->sndcnt == 0){
  1356.                     /* Our FIN has been acked; bypass CLOSING state */
  1357.                     setstate(tcb,TIME_WAIT);
  1358.                     tcb->timer.start = MSL2;
  1359.                     start_timer(&tcb->timer);
  1360.                 } else {
  1361.                     setstate(tcb,CLOSING);
  1362.                 }
  1363.                 break;
  1364.             case FINWAIT2:
  1365.                 tcb->rcv.nxt++;
  1366.                 setstate(tcb,TIME_WAIT);
  1367.                 tcb->timer.start = MSL2;
  1368.                 start_timer(&tcb->timer);
  1369.                 break;
  1370.             case CLOSE_WAIT:
  1371.             case CLOSING:
  1372.             case LAST_ACK:
  1373.                 break;        /* Ignore */
  1374.             case TIME_WAIT:    /* p 76 */
  1375.                 start_timer(&tcb->timer);
  1376.                 break;
  1377.             }
  1378.         }
  1379.         /* Scan the resequencing queue, looking for a segment we can handle,
  1380.          * and freeing all those that are now obsolete.
  1381.          */
  1382.         while(tcb->reseq != NULLRESEQ && seq_ge(tcb->rcv.nxt,tcb->reseq->seg.seq)){
  1383.             get_reseq(tcb,&tos,&seg,&bp,&length);
  1384.             if(trim(tcb,&seg,&bp,&length) == 0)
  1385.                 goto gotone;
  1386.             /* Segment is an old one; trim has freed it */
  1387.         }
  1388.         break;
  1389. gotone:    ;
  1390.     }
  1391.     tcp_output(tcb);    /* Send any necessary ack */
  1392. }
  1393.  
  1394. /* Process an incoming ICMP response */
  1395. tcp_icmp(source,dest,type,code,data)
  1396. int32 source;    /* Original IP datagram source (i.e. us) */
  1397. int32 dest;    /* Original IP datagram dest (i.e., them) */
  1398. char type,code;    /* ICMP error codes */
  1399. char *data;    /* First 8 bytes of TCP header */
  1400. {
  1401.     struct tcp_header *tcph;
  1402.     struct connection conn;
  1403.     register struct tcb *tcb;
  1404.  
  1405.     /* Extract the socket info from the returned TCP header fragment
  1406.      * Note that since this is a datagram we sent, the source fields
  1407.      * refer to the local side.
  1408.      */
  1409.     tcph = (struct tcp_header *)data;
  1410.     conn.local.address = source;
  1411.     conn.local.port = ntohs(tcph->source);
  1412.     conn.remote.address = dest;
  1413.     conn.remote.port = ntohs(tcph->dest);
  1414.     if((tcb = lookup_tcb(&conn)) == NULLTCB)
  1415.         return;    /* Unknown connection, ignore */
  1416.  
  1417.     /* Verify that the sequence number in the returned segment corresponds
  1418.      * to something currently unacknowledged. If not, it can safely
  1419.      * be ignored.
  1420.      */
  1421.     if(!seq_within(ntohl(tcph->seq),tcb->snd.una,tcb->snd.nxt))
  1422.         return;
  1423.  
  1424.     /* The strategy here is that Destination Unreachable and Time Exceeded
  1425.      * messages that occur after a connection has been established are likely
  1426.      * to be transient events, and shouldn't kill our connection (at least
  1427.      * until after we've tried a few more times). On the other hand, if
  1428.      * they occur on our very first attempt to send a datagram on a new
  1429.      * connection, they're probably "for real". In any event, the info
  1430.      * is saved.
  1431.      */
  1432.     switch(type){
  1433.     case DEST_UNREACH:
  1434.     case TIME_EXCEED:
  1435.         tcb->type = type;
  1436.         tcb->code = code;
  1437.         if(tcb->state == SYN_SENT || tcb->state == SYN_RECEIVED){
  1438.             close_self(tcb,NETWORK);
  1439.         }
  1440.         break;
  1441.     case QUENCH:
  1442.         break;        /* I really ought to implement this */
  1443.     }
  1444. }
  1445.  
  1446. /* Send an acceptable reset (RST) response for this segment */
  1447. static void
  1448. reset(source,dest,tos,length,seg)
  1449. int32 source;    /* Remote IP address */
  1450. int32 dest;        /* Our IP address */
  1451. char tos;        /* Type of Service */
  1452. int16 length;    /* Length of data portion */
  1453. register struct tcp_header *seg;    /* Offending TCP header */
  1454. {
  1455.     struct mbuf *hbp;
  1456.     struct pseudo_header ph;
  1457.     register struct tcp_header *tcph;
  1458.  
  1459.     if(seg->flags & RST)
  1460.         return;    /* Never send an RST in response to an RST */
  1461.  
  1462.     tcp_stat.resets++;
  1463.     /* Compose the RST IP pseudo-header, swapping addresses */
  1464.     ph.source = dest;
  1465.     ph.dest = source;
  1466.     ph.protocol = TCP_PTCL;
  1467.     ph.zero = 0;
  1468.     ph.length = sizeof(struct tcp_header);
  1469.  
  1470.     /* Allocate mbuf for the RST TCP header and fill it in */
  1471.     if((hbp = alloc_mbuf(ph.length)) == NULLBUF)
  1472.         return;    /* Can't do nothin' */
  1473.  
  1474.     hbp->cnt = ph.length;
  1475.     tcph = (struct tcp_header *)hbp->data;
  1476.  
  1477.     tcph->source = htons(seg->dest);
  1478.     tcph->dest = htons(seg->source);
  1479.     tcph->flags = RST;
  1480.  
  1481.     if(seg->flags & ACK){
  1482.         /* This reset is being sent to clear a half-open connection.
  1483.          * Set the sequence number of the RST to the incoming ACK
  1484.          * so it will be acceptable.
  1485.          */
  1486.         tcph->seq = htonl(seg->ack);
  1487.         tcph->ack = 0;
  1488.     } else {
  1489.         /* We're rejecting a connect request (SYN) from LISTEN state
  1490.          * so we have to "acknowledge" their SYN.
  1491.          */
  1492.         tcph->seq = 0;
  1493.         if(seg->flags & SYN)
  1494.             length++;
  1495.         if(seg->flags & FIN)
  1496.             length++;
  1497.         tcph->ack = htonl((int32)(seg->seq + length));
  1498.         tcph->flags |= ACK;
  1499.     }
  1500.     tcph->offset = (ph.length/sizeof(long)) << DSHIFT;
  1501.     tcph->wnd = 0;
  1502.     tcph->checksum = 0;
  1503.     tcph->up = 0;
  1504.     tcph->checksum = cksum(&ph,hbp,ph.length);
  1505.     /* Ship it out (note swap of addresses) */
  1506.     ip_send(dest,source,TCP_PTCL,tos,0,hbp,ph.length,0,0);
  1507. }
  1508.  
  1509. /* Process an incoming acknowledgement and window indication.
  1510.  * From page 72.
  1511.  */
  1512. static void
  1513. update(tcb,seg)
  1514. register struct tcb *tcb;
  1515. register struct tcp_header *seg;
  1516. {
  1517.     int16 acked;
  1518.     int32 rtt;
  1519.  
  1520.     acked = 0;
  1521.     if(seq_gt(seg->ack,tcb->snd.nxt)){
  1522.         tcb->force = 1;    /* Acks something not yet sent */
  1523.         return;
  1524.     }
  1525.     /* Round trip time estimation */
  1526.     if(seq_gt(tcb->rttseq,tcb->snd.una)){
  1527.         /* A sequence number is actively being timed */
  1528.         if(tcb->retry == 0 && seq_ge(seg->ack,tcb->rttseq)){
  1529.             /* This packet was sent only once and now
  1530.              * it's been acked, so compute the new smoothed
  1531.              * estimate. The RT time is just the current time
  1532.              * on the retransmission timer.
  1533.              */
  1534.             rtt = tcb->timer.start - tcb->timer.count;
  1535.             rtt *= MSPTICK;    /* convert to ticks */
  1536.             /* Fast attack/slow decay algorithm by Dave Mills
  1537.              * (see RFC-889)
  1538.              */
  1539.             if(rtt > tcb->srtt){
  1540.                 /* RTT is increasing, use fast attack */
  1541.                 tcb->srtt = (ALPHA1*tcb->srtt + rtt)/(ALPHA1+1);
  1542.             } else {
  1543.                 /* RTT is decreasing, use slow decay */
  1544.                 tcb->srtt = (ALPHA2*tcb->srtt + rtt)/(ALPHA2+1);
  1545.             }
  1546.             /* Set new retransmission timeout */
  1547.             tcb->timer.start = (BETA * tcb->srtt)/MSPTICK;
  1548.         }
  1549.     }
  1550.     /* If the remote window is closed, reset the retry counter even if
  1551.      * this packet doesn't acknowledge anything new as long as the ACK
  1552.      * is current.
  1553.      * This allows closed-window probes to go on indefinitely.
  1554.      */
  1555.     if(seg->wnd == 0 && seq_ge(seg->ack,tcb->snd.una))
  1556.         tcb->retry = 0;
  1557.  
  1558.     /* See if anything new is being acknowledged */
  1559.     if(seq_gt(seg->ack,tcb->snd.una)){
  1560.         acked = seg->ack - tcb->snd.una;
  1561.         /* If we're waiting for an ack of our SYN, process it */
  1562.         switch(tcb->state){
  1563.         case SYN_SENT:
  1564.         case SYN_RECEIVED:
  1565.             acked--;
  1566.             tcb->sndcnt--;
  1567.         }
  1568.         /* Remove acknowledged bytes from the send queue and update the
  1569.          * unacknowledged pointer. If a FIN is being acked,
  1570.          * pullup won't be able to remove it from the queue.
  1571.          */
  1572.         pullup(&tcb->sndq,NULLCHAR,acked);
  1573.  
  1574.         /* This will include the FIN if there is one */
  1575.         tcb->sndcnt -= acked;
  1576.         tcb->snd.una = seg->ack;
  1577.  
  1578.         /* If retransmissions have been occurring, make sure the
  1579.          * send pointer doesn't repeat ancient history
  1580.          */
  1581.         if(seq_lt(tcb->snd.ptr,tcb->snd.una))
  1582.             tcb->snd.ptr = tcb->snd.una;
  1583.  
  1584.         /* Reset the retry counter */
  1585.         tcb->retry = 0;
  1586.         /* Stop retransmission timer, but restart it if there is still
  1587.          * unacknowledged data
  1588.          */    
  1589.         stop_timer(&tcb->timer);
  1590.         if(tcb->snd.una != tcb->snd.nxt){
  1591.             start_timer(&tcb->timer);
  1592.         }
  1593.     }
  1594.     /* Decide if we need to do a window update.
  1595.      * This is always checked whenever a legal ACK is received,
  1596.      * because it might be a spontaneous window reopening.
  1597.      */
  1598.     if(seq_gt(seg->seq,tcb->snd.wl1) || ((seg->seq == tcb->snd.wl1) 
  1599.      && seq_ge(seg->ack,tcb->snd.wl2))){
  1600.         /* If the window had been closed, crank back the
  1601.          * send pointer so we'll immediately resume transmission.
  1602.          * Otherwise we'd have to wait until the next probe.
  1603.          */
  1604.         if(tcb->snd.wnd == 0 && seg->wnd != 0)
  1605.             tcb->snd.ptr = tcb->snd.una;
  1606.         tcb->snd.wnd = seg->wnd;
  1607.         tcb->snd.wl1 = seg->seq;
  1608.         tcb->snd.wl2 = seg->ack;
  1609.     }
  1610.     /* If outgoing data was acked, notify the user so he can send more
  1611.      * unless we've already sent a FIN.
  1612.      */
  1613.     if(acked != 0 && tcb->t_upcall){
  1614.         switch(tcb->state){
  1615.          case ESTABLISHED:
  1616.         case CLOSE_WAIT:
  1617.             (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  1618.         }
  1619.     }
  1620. }
  1621.  
  1622. /* Determine if the given sequence number is in our receiver window.
  1623.  * NB: must not be used when window is closed!
  1624.  */
  1625. static
  1626. int
  1627. in_window(tcb,seq)
  1628. struct tcb *tcb;
  1629. int32 seq;
  1630. {
  1631.     return seq_within(seq,tcb->rcv.nxt,(int32)(tcb->rcv.nxt+tcb->rcv.wnd-1));
  1632. }
  1633.  
  1634. /* Process an incoming SYN */
  1635. static void
  1636. proc_syn(tcb,tos,seg,mss)
  1637. register struct tcb *tcb;
  1638. char tos;
  1639. struct tcp_header *seg;
  1640. int16 mss;
  1641. {
  1642.     int16 mtu,ip_mtu();
  1643.  
  1644.     tcb->force = 1;    /* Always send a response */
  1645.  
  1646.     /* Note: It's not specified in RFC 793, but SND.WL1 and
  1647.      * SND.WND are initialized here since it's possible for the
  1648.      * window update routine in update() to fail depending on the
  1649.      * IRS if they are left unitialized.
  1650.      */
  1651.     /* Check incoming precedence and increase if higher */
  1652.     if(PREC(tos) > PREC(tcb->tos))
  1653.         tcb->tos = tos;
  1654.     tcb->rcv.nxt = seg->seq + 1;    /* p 68 */
  1655.     tcb->snd.wl1 = tcb->irs = seg->seq;
  1656.     tcb->snd.wnd = seg->wnd;
  1657.     if(mss != 0)
  1658.         tcb->mss = mss;
  1659.     /* Check the MTU of the interface we'll use to reach this guy
  1660.      * and lower the MSS so that unnecessary fragmentation won't occur
  1661.      */
  1662.     if((mtu = ip_mtu(tcb->conn.remote.address)) != 0){
  1663.         /* Allow space for the TCP and IP headers */
  1664.         mtu -= sizeof(struct tcp_header) + sizeof(struct ip_header);
  1665.         tcb->mss = min(mtu,tcb->mss);
  1666.     }
  1667. }
  1668.  
  1669. /* Generate an initial sequence number and put a SYN on the send queue */
  1670. void
  1671. send_syn(tcb)
  1672. register struct tcb *tcb;
  1673. {
  1674.     tcb->iss = iss();
  1675.     tcb->rttseq = tcb->snd.ptr = tcb->snd.wl2 = tcb->snd.nxt = tcb->snd.una = tcb->iss;
  1676.     tcb->sndcnt++;
  1677.     tcb->force = 1;
  1678. }
  1679.  
  1680. /* Add an entry to the resequencing queue in the proper place */
  1681. static void
  1682. add_reseq(tcb,tos,seg,bp,length)
  1683. struct tcb *tcb;
  1684. char tos;
  1685. struct tcp_header *seg;
  1686. struct mbuf *bp;
  1687. int16 length;
  1688. {
  1689.     register struct reseq *rp,*rp1;
  1690.     char *malloc();
  1691.  
  1692.     /* Allocate reassembly descriptor */
  1693.     if((rp = (struct reseq *)malloc(sizeof (struct reseq))) == NULLRESEQ){
  1694.         /* No space, toss on floor */
  1695.         free_p(bp);
  1696.         return;
  1697.     }
  1698.     bcopy((char *)seg,(char *)&rp->seg,sizeof(struct tcp_header));
  1699.     rp->tos = tos;
  1700.     rp->bp = bp;
  1701.     rp->length = length;
  1702.  
  1703.     /* Place on reassembly list sorting by starting seq number */
  1704.     rp1 = tcb->reseq;
  1705.     if(rp1 == NULLRESEQ || seq_lt(seg->seq,rp1->seg.seq)){
  1706.         /* Either the list is empty, or we're less than all other
  1707.          * entries; insert at beginning.
  1708.          */
  1709.         rp->next = rp1;
  1710.         tcb->reseq = rp;
  1711.     } else {
  1712.         /* Find the last entry less than us */
  1713.         for(;;){
  1714.             if(rp1->next == NULLRESEQ || seq_lt(seg->seq,rp1->next->seg.seq)){
  1715.                 /* We belong just after this one */
  1716.                 rp->next = rp1->next;
  1717.                 rp1->next = rp;
  1718.                 break;
  1719.             }
  1720.             rp1 = rp1->next;
  1721.         }
  1722.     }
  1723. }
  1724.  
  1725. /* Fetch the first entry off the resequencing queue */
  1726. static void
  1727. get_reseq(tcb,tos,seg,bp,length)
  1728. register struct tcb *tcb;
  1729. char *tos;
  1730. struct tcp_header *seg;
  1731. struct mbuf **bp;
  1732. int16 *length;
  1733. {
  1734.     register struct reseq *rp;
  1735.  
  1736.     if((rp = tcb->reseq) == NULLRESEQ)
  1737.         return;
  1738.  
  1739.     tcb->reseq = rp->next;
  1740.  
  1741.     *tos = rp->tos;
  1742.     bcopy((char *)&rp->seg,(char *)seg,sizeof(struct tcp_header));
  1743.     *bp = rp->bp;
  1744.     *length = rp->length;
  1745.     free((char *)rp);
  1746. }
  1747.  
  1748. /* Trim segment to fit window. Return 0 if OK, -1 if segment is
  1749.  * unacceptable.
  1750.  */
  1751. static int
  1752. trim(tcb,seg,bp,length)
  1753. register struct tcb *tcb;
  1754. register struct tcp_header *seg;
  1755. struct mbuf **bp;
  1756. int16 *length;
  1757. {
  1758.     struct mbuf *nbp;
  1759.     long dupcnt,excess;
  1760.     int16 len;        /* Segment length including flags */
  1761.     char accept;
  1762.  
  1763.     accept = 0;
  1764.     len = *length;
  1765.     if(seg->flags & SYN)
  1766.         len++;
  1767.     if(seg->flags & FIN)
  1768.         len++;
  1769.  
  1770.     /* Acceptability tests */
  1771.     if(tcb->rcv.wnd == 0){
  1772.         /* Only in-order, zero-length segments are acceptable when our window
  1773.          * is closed.
  1774.          */
  1775.         if(seg->seq == tcb->rcv.nxt && len == 0){
  1776.             return 0;    /* Acceptable, no trimming needed */
  1777.         }
  1778.     } else {
  1779.         /* Some part of the segment must be in the window */
  1780.         if(in_window(tcb,seg->seq)){
  1781.             accept++;    /* Beginning is */
  1782.         } else if(len != 0){
  1783.             if(in_window(tcb,(int32)(seg->seq+len-1)) || /* End is */
  1784.              seq_within(tcb->rcv.nxt,seg->seq,(int32)(seg->seq+len-1))){ /* Straddles */
  1785.                 accept++;
  1786.             }
  1787.         }
  1788.     }
  1789.     if(!accept){
  1790.         free_p(*bp);
  1791.         return -1;
  1792.     }
  1793.     dupcnt = tcb->rcv.nxt - seg->seq;
  1794.     if(dupcnt > 0){
  1795.         /* Trim off SYN if present */
  1796.         if(seg->flags & SYN){
  1797.             /* SYN is before first data byte */
  1798.             seg->flags &= ~SYN;
  1799.             seg->seq++;
  1800.             dupcnt--;
  1801.         }
  1802.         if(dupcnt > 0){
  1803.             pullup(bp,NULLCHAR,(int16)dupcnt);
  1804.             seg->seq += dupcnt;
  1805.             *length -= dupcnt;
  1806.         }
  1807.     }
  1808.     excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd);
  1809.     if(excess > 0){
  1810.         /* Trim right edge */
  1811.         *length -= excess;
  1812.         nbp = copy_p(*bp,*length);
  1813.         free_p(*bp);
  1814.         *bp = nbp;
  1815.         seg->flags &= ~FIN;    /* FIN follows last data byte */
  1816.     }
  1817.     return 0;
  1818. }
  1819. SHAR_EOF
  1820. cat << \SHAR_EOF > newtelnetp.c
  1821. #include <stdio.h>
  1822. #include <exec/types.h>
  1823. #include <exec/nodes.h>
  1824. #include <exec/lists.h>
  1825. #include <exec/tasks.h>
  1826. #include <exec/ports.h>
  1827. #include <exec/libraries.h>
  1828. #include <exec/io.h>
  1829. #include <exec/devices.h>
  1830. #include <exec/errors.h>
  1831. #include <proto/exec.h>
  1832. #include <devices/console.h>
  1833. #include <libraries/dos.h>
  1834. #include <libraries/dosextens.h>
  1835. #include <intuition/intuition.h>
  1836. #include <dos.h>
  1837. #include "machdep.h"
  1838. #include "mbuf.h"
  1839. #include "timer.h"
  1840. #include "internet.h"
  1841. #include "icmp.h"
  1842. #include "netuser.h"
  1843. #include "tcp.h"
  1844. #include "telnet.h"
  1845. #include "session.h"
  1846. #include "inetdev.h"
  1847. #include "inetlib.h"
  1848. #define DEBUG
  1849. struct Process *mytask;
  1850. APTR    oldwindowptr;
  1851. struct IntuitionBase *IntuitionBase;
  1852. char banner[80] = "telnet window";
  1853. static struct NewWindow nw = {
  1854.     0, 0, 640, 200,        /* left, top, (max) width, (max) height */
  1855.     0, 1,            /* detail pen, block pen */
  1856.     0,            /* IDCMP flags */
  1857.     SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING |
  1858.         SIZEBBOTTOM | ACTIVATE | NOCAREREFRESH,    /* window flags */
  1859.     NULL, NULL,        /* gadget, checkmark */
  1860.     (UBYTE *)&banner[0],    /* title of window */
  1861.     NULL, NULL,        /* screen, bitmap */
  1862.     200, 50, -1, -1,    /* sizing limits */
  1863.     WBENCHSCREEN,        /* on the workbench */
  1864. };
  1865. struct Window *win;
  1866. struct MsgPort *keyboard, *consinp, *consoutp, *tcpinp, *tcpoutp;
  1867. struct IOStdReq consin, consout;
  1868. char InputCharacter;
  1869. int deviceopened = 0;
  1870. struct IOINETReq tnreq, tninreq, tnoutreq;
  1871. char recv[512], snd[512], recvbuf[512], tcpinbuf[512];
  1872. struct telnet *tn;
  1873. #ifdef LATTICE
  1874. extern struct { short error; char *msg; } os_errlist[];
  1875. extern int _OSERR, os_nerr;
  1876. #endif
  1877. static
  1878. /*
  1879.  * wait for something to happen
  1880.  */
  1881. eihalt()
  1882. {
  1883.     register struct IntuiMessage *msg;
  1884.     static ULONG mask = 0;
  1885.  
  1886.     if (mask == 0L)
  1887.         mask =     1L << consinp->mp_SigBit |
  1888.             1L << tcpinp->mp_SigBit;
  1889.  
  1890.     (void) Wait(mask);
  1891. }
  1892. clean(why)
  1893.     char *why;
  1894. {
  1895.     int i;
  1896.  
  1897.     if (win)
  1898.         CloseWindow(win);
  1899.     if (consinp)
  1900.         DeletePort(consinp);
  1901.     if (consoutp)
  1902.         DeletePort(consoutp);
  1903.     if (tcpinp)
  1904.         DeletePort(tcpinp);
  1905.     if (tcpoutp)
  1906.         DeletePort(tcpoutp);
  1907.     if (deviceopened)
  1908.         CloseDevice(&tnreq);
  1909.     mytask->pr_WindowPtr = oldwindowptr;
  1910.     if (why) {
  1911.            myoserr(why);
  1912.     }
  1913.     exit(0);
  1914. }
  1915. printlist(l)
  1916. struct List *l;
  1917. {
  1918.   printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail, 
  1919.         l->lh_TailPred);
  1920. }
  1921. myoserr(why)
  1922. char *why;
  1923. {
  1924.   int i;
  1925.         fprintf(stderr, "%s: ", why); 
  1926. #ifdef LATTICE
  1927.         fprintf(stderr, "%d: ", _OSERR);
  1928.  
  1929.         for(i = 0; os_errlist[i].error < os_nerr; i++)
  1930.           if (os_errlist[i].error == _OSERR)
  1931.             fprintf(stderr, os_errlist[i].msg);
  1932. #endif
  1933.         fprintf(stderr, "\r\n");
  1934. }
  1935. /* Called at startup time to set up console I/O, memory heap */
  1936. ioinit()
  1937. {
  1938.     struct Screen *scr;
  1939.  
  1940.     mytask = (struct Process *) FindTask((char *) NULL);
  1941.     oldwindowptr = mytask->pr_WindowPtr;
  1942.     mytask->pr_WindowPtr = (APTR) -1;    /* disable DOS requestors */
  1943.  
  1944.     if ((IntuitionBase = (struct IntuitionBase *)
  1945.        OpenLibrary("intuition.library", 33L)) == NULL)
  1946.         clean("No intuition: Version 1.2 of Amiga Systems Software required");
  1947.     /*
  1948.      *  Try to determine the size of the workbench screen
  1949.      */
  1950.     scr = malloc(sizeof(struct Screen));
  1951.     if (scr==NULL)
  1952.         clean("Can't alloc screen");
  1953.  
  1954.     if (GetScreenData(scr, (ULONG) sizeof(struct Screen),
  1955.               WBENCHSCREEN, NULL) == TRUE) {
  1956.         nw.Width = scr->Width;
  1957.         nw.Height = scr->Height-20;
  1958.         nw.TopEdge = 19;
  1959.     } else
  1960.         fprintf(stderr, "Can't GetScreenData()\n");
  1961.  
  1962.     free((char *)scr);
  1963.     if ((win = OpenWindow(&nw)) == NULL)
  1964.         clean("Can't open window");
  1965.     if ((consinp = CreatePort("telnet:console in", 0L)) == NULL)
  1966.         clean("Can't create console port");
  1967.     if ((tcpinp = CreatePort("telnet:tcp in", 0L)) == NULL)
  1968.         clean("Can't create telnet tcp input port");
  1969.     if ((tcpoutp = CreatePort("telnet:tcp out", 0L)) == NULL)
  1970.         clean("Can't create telnet tcp output port");
  1971.  
  1972.     consin.io_Data = (APTR) win;
  1973.     consin.io_Length = sizeof(struct Window);
  1974.  
  1975.     _OSERR = OpenDevice("console.device", 0L, &consin, 0L);
  1976.     if (_OSERR != 0L){
  1977.         printf("opendevice returned %d\n", _OSERR);
  1978.         myoserr("could not get console");
  1979.         clean("Can't open console device");
  1980.     }
  1981.     consout = consin;
  1982.  
  1983.     consin.io_Message.mn_ReplyPort = consinp;
  1984.     consin.io_Length = 512;
  1985.     consin.io_Data = (APTR) recvbuf;
  1986.     consin.io_Command = CMD_READ;
  1987.     SendIO(&consin);
  1988.     consout.io_Message.mn_ReplyPort = consoutp;
  1989.     consout.io_Command = CMD_WRITE;
  1990.  
  1991.  
  1992. }
  1993. /* Read characters from the keyboard, translating them to "real" ASCII
  1994.  * If none are ready, return the -1 from kbraw()
  1995.  */
  1996. kbread()
  1997. {
  1998.     char c;
  1999.     int amount;
  2000.  
  2001.     if (CheckIO(&consin)) {
  2002.         WaitIO(&consin);
  2003.         amount = consin.io_Actual;
  2004.         if (amount > 512)
  2005.           amount = 511;
  2006.         strncpy(recv, recvbuf, amount);
  2007.         SendIO(&consin);
  2008.         return (amount);
  2009.     }
  2010.  
  2011.     return -1;        /* nuthin here */
  2012. }
  2013. extern char nospace[];
  2014. int refuse_echo = 0;
  2015. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  2016.  
  2017. #ifdef    DEBUG
  2018. char *t_options[] = {
  2019.     "Transmit Binary",
  2020.     "Echo",
  2021.     "",
  2022.     "Suppress Go Ahead",
  2023.     "",
  2024.     "Status",
  2025.     "Timing Mark"
  2026. };
  2027. #endif
  2028. /* Telnet receiver upcall routine */
  2029. void
  2030. rcv_char()
  2031. {
  2032.     tel_input(tn,tninreq.io_Data, tninreq.io_Actual);
  2033.     fflush(stdout);
  2034. }
  2035. brk()
  2036. {
  2037.   clean("ok i iwll quit\n");
  2038. }
  2039. /* TCP connection states */
  2040. char *tcpstates[] = {
  2041.     "Closed",
  2042.     "Listen",
  2043.     "SYN sent",
  2044.     "SYN received",
  2045.     "Established",
  2046.     "FIN wait 1",
  2047.     "FIN wait 2",
  2048.     "Close wait",
  2049.     "Closing",
  2050.     "Last ACK",
  2051.     "Time wait"
  2052. };
  2053. /* TCP segment header flags */
  2054. char *tcpflags[] = {
  2055.     "FIN",    /* 0x01 */
  2056.     "SYN",    /* 0x02 */
  2057.     "RST",    /* 0x04 */
  2058.     "PSH",    /* 0x08 */
  2059.     "ACK",    /* 0x10 */
  2060.     "URG"    /* 0x20 */
  2061. };
  2062.  
  2063. /* TCP closing reasons */
  2064. char *reasons[] = {
  2065.     "Normal",
  2066.     "Reset",
  2067.     "Timeout",
  2068.     "ICMP"
  2069. };
  2070. char old = LISTEN;
  2071. int done = 0;
  2072. char *hostname="";
  2073. int hostport=0;
  2074. char *bannerfmt = "telnet %10s %4d %10s";
  2075. void
  2076. showstate(old, new)
  2077.     char old, new;
  2078. {
  2079.  
  2080.  
  2081.     /* Can't add a check for unknown connection here, it would loop
  2082.      * on a close upcall! We're just careful later on.
  2083.      */
  2084.  
  2085.     sprintf(banner, bannerfmt, hostname, hostport, tcpstates[new]);
  2086.     SetWindowTitles(win, banner, -1);
  2087.     switch(new){
  2088.     case CLOSE_WAIT:
  2089.         done = 1;
  2090.         break;
  2091.     case CLOSED:    /* court adjourned */
  2092.         done = 1;
  2093.         break;
  2094.     default:
  2095.         break;
  2096.     }
  2097.     fflush(stdout);
  2098.  
  2099. }
  2100.  
  2101. /* Execute user telnet command */
  2102. main(argc,argv)
  2103. int argc;
  2104. char *argv[];
  2105. {
  2106.     extern int _OSERR;
  2107.     struct InternetBase *InternetBase;
  2108.     int send_tel();
  2109.         int unix_send_tel();
  2110.     struct session *s;
  2111.     int amount;
  2112.     struct socket lsocket,fsocket;
  2113.     ioinit();
  2114.     hostname = argv[1];
  2115.     old = LISTEN;
  2116.     showstate(old, LISTEN);
  2117.     tnreq.io_fsocket.address = aton(argv[1]);
  2118.     if(argc < 3)
  2119.         tnreq.io_fsocket.port = TELNET_PORT;
  2120.     else
  2121.         tnreq.io_fsocket.port = atoi(argv[2]);
  2122.     tnreq.io_Device = NULL;
  2123.     tnreq.io_Unit = NULL;
  2124.     tnreq.io_Flags = 0;
  2125.     tnreq.io_Error = 0;
  2126.     InternetBase = (struct InternetBase *) OpenDevice("internet.device",
  2127.                 (long) INET_UNIT_TCP, &tnreq, 0L);
  2128.     if (InternetBase != 0L){
  2129.       printf("it did not open %d\n",InternetBase);
  2130.       clean("i quit");
  2131.     }
  2132.     hostport = tnreq.io_lsocket.port;
  2133.     deviceopened = 1;
  2134.     tninreq = tnreq; /* possible lettuce bug  ?*/
  2135.     tnoutreq = tnreq;
  2136.     tninreq.io_Length = 512;
  2137.     tnoutreq.io_Length = 1;
  2138.     tninreq.io_Data = tcpinbuf;
  2139.     tnoutreq.io_Data = snd;
  2140.     tnoutreq.io_Length = 0;
  2141.     tninreq.io_Command = CMD_READ;
  2142.     tnoutreq.io_Command = CMD_WRITE;
  2143.     tninreq.io_Message.mn_ReplyPort = tcpinp;
  2144.     tnoutreq.io_Message.mn_ReplyPort = tcpoutp;
  2145.     /* Create and initialize a Telnet protocol descriptor */
  2146.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  2147.         myoserr("calloc faiuled\n");
  2148.         goto done;
  2149.     }
  2150.     tn->session = s;    /* Upward pointer */
  2151.     tn->state = TS_DATA;
  2152.         SendIO(&tninreq);
  2153.     onbreak(&brk);
  2154.     InputCharacter = ' ';
  2155.     while (! done)
  2156.       {
  2157.         eihalt();
  2158.         if ((amount = kbread()) >= 0){
  2159.           
  2160.           unix_send_tel(recv, amount);}
  2161.  
  2162.         if (CheckIO(&tninreq))
  2163.           {
  2164.         chkabort();
  2165.         WaitIO(&tninreq);
  2166.             rcv_char();
  2167.             if (tninreq.io_State != old)
  2168.               {
  2169.             showstate(old, tninreq.io_State);
  2170.             old = tninreq.io_State;
  2171.               }
  2172.                 SendIO(&tninreq);
  2173.           }
  2174.       }
  2175. done:
  2176.     clean("All done");          
  2177.  
  2178. }
  2179.  
  2180. /* Process typed characters */
  2181. int
  2182. unix_send_tel(buf,n)
  2183. char *buf;
  2184. int16 n;
  2185. {
  2186.     int i;
  2187.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  2188.         ;
  2189.     if (buf[i] == '\r') {
  2190.         buf[i] = '\n';
  2191.         n = i+1;
  2192.     }
  2193.     send_tel(buf,n);
  2194. }
  2195. int
  2196. send_tel(buf,n)
  2197. char *buf;
  2198. int16 n;
  2199. {
  2200.     int i;
  2201.  
  2202.     tnoutreq.io_Data = buf;
  2203.     tnoutreq.io_Length = n;
  2204.  
  2205.     SendIO(&tnoutreq);
  2206.     i = WaitIO(&tnoutreq); 
  2207.     if (tnoutreq.io_State != old)
  2208.       {
  2209.         showstate(old, tnoutreq.io_State);
  2210.         old = tnoutreq.io_State;
  2211.       }
  2212.  
  2213. }
  2214.  
  2215. /* Process incoming TELNET characters */
  2216. int
  2217. tel_input(tn,bp, len)
  2218. register struct telnet *tn;
  2219. char *bp;
  2220. int len;
  2221. {
  2222.     char c;
  2223.     int ci;
  2224.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  2225. #ifdef    FAST    /* DON'T USE -- Aztec memchr() routine is broken */
  2226.     char *memchr();
  2227.  
  2228.     /* Optimization for very common special case -- no command chars */
  2229.     if(tn->state == TS_DATA){
  2230.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) 
  2231.             == NULLCHAR){
  2232.             fflush(stdout);
  2233.             write(1,bp->data,bp->cnt);
  2234.             bp = free_mbuf(bp);
  2235.         }
  2236.     }
  2237. #endif
  2238.     while(len--){
  2239.         c = *bp++;
  2240.         ci = c & 0xff;
  2241.         switch(tn->state){
  2242.         case TS_DATA:
  2243.             if(ci == IAC){
  2244.                 tn->state = TS_IAC;
  2245.             } else {
  2246.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  2247.                     c &= 0x7f;
  2248.                 putchar(c);
  2249.             }
  2250.             break;
  2251.         case TS_IAC:
  2252.             switch(ci){
  2253.             case WILL:
  2254.                 tn->state = TS_WILL;
  2255.                 break;
  2256.             case WONT:
  2257.                 tn->state = TS_WONT;
  2258.                 break;
  2259.             case DO:
  2260.                 tn->state = TS_DO;
  2261.                 break;
  2262.             case DONT:
  2263.                 tn->state = TS_DONT;
  2264.                 break;
  2265.             case IAC:
  2266.                 putchar(c);
  2267.                 tn->state = TS_DATA;
  2268.                 break;
  2269.             default:
  2270.                 tn->state = TS_DATA;
  2271.                 break;
  2272.             }
  2273.             break;
  2274.         case TS_WILL:
  2275.             willopt(tn,ci);
  2276.             tn->state = TS_DATA;
  2277.             break;
  2278.         case TS_WONT:
  2279.             wontopt(tn,ci);
  2280.             tn->state = TS_DATA;
  2281.             break;
  2282.         case TS_DO:
  2283.             doopt(tn,ci);
  2284.             tn->state = TS_DATA;
  2285.             break;
  2286.         case TS_DONT:
  2287.             dontopt(tn,ci);
  2288.             tn->state = TS_DATA;
  2289.             break;
  2290.         }
  2291.     }
  2292. }
  2293.  
  2294. #ifdef NOTDEF
  2295. /* State change upcall routine */
  2296. void
  2297. t_state(tcb,old,new)
  2298. register struct tcb *tcb;
  2299. char old,new;
  2300. {
  2301.     struct telnet *tn;
  2302.     char notify = 0;
  2303.     extern char *tcpstates[];
  2304.     extern char *reasons[];
  2305.     extern char *unreach[];
  2306.     extern char *exceed[];
  2307.  
  2308.     /* Can't add a check for unknown connection here, it would loop
  2309.      * on a close upcall! We're just careful later on.
  2310.      */
  2311.     tn = (struct telnet *)tcb->user;
  2312.  
  2313.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  2314.         notify = 1;
  2315.  
  2316.     switch(new){
  2317.     case CLOSE_WAIT:
  2318.         if(notify)
  2319.             printf("%s\r\n",tcpstates[new]);
  2320.         close_tcp(tcb);
  2321.         break;
  2322.     case CLOSED:    /* court adjourned */
  2323.         if(notify){
  2324.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  2325.             if(tcb->reason == NETWORK){
  2326.                 switch(tcb->type){
  2327.                 case DEST_UNREACH:
  2328.                     printf(": %s unreachable",unreach[tcb->code]);
  2329.                     break;
  2330.                 case TIME_EXCEED:
  2331.                     printf(": %s time exceeded",exceed[tcb->code]);
  2332.                     break;
  2333.                 }
  2334.             }
  2335.             printf(")\r\n");
  2336.             cmdmode();
  2337.         }
  2338.         del_tcp(tcb);
  2339.         if(tn != NULLTN)
  2340.             free_telnet(tn);
  2341.         break;
  2342.     default:
  2343.         if(notify)
  2344.             printf("%s\r\n",tcpstates[new]);
  2345.         break;
  2346.     }
  2347.     fflush(stdout);
  2348. }
  2349. #endif
  2350. /* Delete telnet structure */
  2351. static
  2352. free_telnet(tn)
  2353. struct telnet *tn;
  2354. {
  2355.  
  2356.     if(tn != NULLTN)
  2357.         free((char *)tn);
  2358. }
  2359.  
  2360. /* The guts of the actual Telnet protocol: negotiating options */
  2361. static
  2362. void
  2363. willopt(tn,opt)
  2364. struct telnet *tn;
  2365. int opt;
  2366. {
  2367.     int ack;
  2368.     void answer();
  2369.  
  2370. #ifdef    DEBUG
  2371.     printf("recv: will ");
  2372.     if(opt <= NOPTIONS)
  2373.         printf("%s\r\n",t_options[opt]);
  2374.     else
  2375.         printf("%u\r\n",opt);
  2376. #endif
  2377.     
  2378.     switch(opt){
  2379.     case TN_TRANSMIT_BINARY:
  2380.     case TN_ECHO:
  2381.     case TN_SUPPRESS_GA:
  2382.         if(tn->remote[opt] == 1)
  2383.             return;        /* Already set, ignore to prevent loop */
  2384.         if(opt == TN_ECHO){
  2385.             if(refuse_echo){
  2386.                 /* User doesn't want to accept */
  2387.                 ack = DONT;
  2388.                 break;
  2389.             } else
  2390.                 raw();        /* Put tty into raw mode */
  2391.         }
  2392.         tn->remote[opt] = 1;
  2393.         ack = DO;            
  2394.         break;
  2395.     default:
  2396.         ack = DONT;    /* We don't know what he's offering; refuse */
  2397.     }
  2398.     answer(tn,ack,opt);
  2399. }
  2400. static
  2401. void
  2402. wontopt(tn,opt)
  2403. struct telnet *tn;
  2404. int opt;
  2405. {
  2406.     void answer();
  2407.  
  2408. #ifdef    DEBUG
  2409.     printf("recv: wont ");
  2410.     if(opt <= NOPTIONS)
  2411.         printf("%s\r\n",t_options[opt]);
  2412.     else
  2413.         printf("%u\r\n",opt);
  2414. #endif
  2415.     if(opt <= NOPTIONS){
  2416.         if(tn->remote[opt] == 0)
  2417.             return;        /* Already clear, ignore to prevent loop */
  2418.         tn->remote[opt] = 0;
  2419.         if(opt == TN_ECHO)
  2420.             cooked();    /* Put tty into cooked mode */
  2421.     }
  2422.     answer(tn,DONT,opt);    /* Must always accept */
  2423. }
  2424. static
  2425. void
  2426. doopt(tn,opt)
  2427. struct telnet *tn;
  2428. int opt;
  2429. {
  2430.     void answer();
  2431.     int ack;
  2432.  
  2433. #ifdef    DEBUG
  2434.     printf("recv: do ");
  2435.     if(opt <= NOPTIONS)
  2436.         printf("%s\r\n",t_options[opt]);
  2437.     else
  2438.         printf("%u\r\n",opt);
  2439. #endif
  2440.     switch(opt){
  2441. #ifdef    FUTURE    /* Use when local options are implemented */
  2442.         if(tn->local[opt] == 1)
  2443.             return;        /* Already set, ignore to prevent loop */
  2444.         tn->local[opt] = 1;
  2445.         ack = WILL;
  2446.         break;
  2447. #endif
  2448.     default:
  2449.         ack = WONT;    /* Don't know what it is */
  2450.     }
  2451.     answer(tn,ack,opt);
  2452. }
  2453. static
  2454. void
  2455. dontopt(tn,opt)
  2456. struct telnet *tn;
  2457. int opt;
  2458. {
  2459.     void answer();
  2460.  
  2461. #ifdef    DEBUG
  2462.     printf("recv: dont ");
  2463.     if(opt <= NOPTIONS)
  2464.         printf("%s\r\n",t_options[opt]);
  2465.     else
  2466.         printf("%u\r\n",opt);
  2467. #endif
  2468.     if(opt <= NOPTIONS){
  2469.         if(tn->local[opt] == 0){
  2470.             /* Already clear, ignore to prevent loop */
  2471.             return;
  2472.         }
  2473.         tn->local[opt] = 0;
  2474.     }
  2475.     answer(tn,WONT,opt);
  2476. }
  2477. static
  2478. void
  2479. answer(tn,r1,r2)
  2480. struct telnet *tn;
  2481. int r1,r2;
  2482. {
  2483.     struct mbuf *bp,*qdata();
  2484.     char s[3];
  2485.  
  2486. #ifdef    DEBUG
  2487.     switch(r1){
  2488.     case WILL:
  2489.         printf("sent: will ");
  2490.         break;
  2491.     case WONT:
  2492.         printf("sent: wont ");
  2493.         break;
  2494.     case DO:
  2495.         printf("sent: do ");
  2496.         break;
  2497.     case DONT:
  2498.         printf("sent: dont ");
  2499.         break;
  2500.     }
  2501.     if(r2 <= 6)
  2502.         printf("%s\r\n",t_options[r2]);
  2503.     else
  2504.         printf("%u\r\n",r2);
  2505. #endif
  2506.  
  2507.     s[0] = IAC;
  2508.     s[1] = r1;
  2509.     s[2] = r2;
  2510.     tnoutreq.io_Data = s;
  2511.     tnoutreq.io_Length = 3;
  2512.     DoIO(&tnoutreq);
  2513. /*
  2514.     bp = qdata(s,(int16)3);
  2515.     send_tcp(tn->tcb,bp);
  2516. */
  2517. }
  2518.  
  2519. #define    BUFMAXCNT    150
  2520. static char conbuf[BUFMAXCNT];
  2521. static int concnt = 0;
  2522.  
  2523. int
  2524. amigaputchar(c)
  2525.     char c;
  2526. {
  2527.     conbuf[concnt++] = c;
  2528.     if ((c == '\n') || (concnt == BUFMAXCNT))
  2529.         amigaflush();
  2530.     return c;
  2531. }
  2532.  
  2533. amigaflush()
  2534. {
  2535.     if (concnt == 0)
  2536.         return;
  2537.     consout.io_Data = (APTR) conbuf;
  2538.     consout.io_Length = concnt;
  2539.     consout.io_Command = CMD_WRITE;
  2540.     DoIO(&consout);
  2541.     concnt = 0;
  2542. }
  2543.     
  2544. /*
  2545.  *  Begin terrible, horrible hack.  All output should be printed upon (into?)
  2546.  *  the window we opened before.  Here goes nothing...
  2547.  */
  2548.  
  2549. printf(a, b, c, d, e, f, g, h, i, j, k)
  2550.     char *a;
  2551.     int b, c, d, e, f, g, h, i, j, k;
  2552. {
  2553.     if (concnt)
  2554.         amigaflush();
  2555.  
  2556.     sprintf(conbuf, a, b, c, d, e, f, g, h, i, j, k);
  2557.     consout.io_Data = (APTR) conbuf;
  2558.     consout.io_Length = strlen(conbuf);
  2559.     consout.io_Command = CMD_WRITE;
  2560.     DoIO(&consout);        /* no use in doing this async */
  2561. }
  2562. SHAR_EOF
  2563. #    End of shell archive
  2564. exit 0
  2565. -- 
  2566. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2567. Have five nice days.
  2568.